﻿/* 2013/1/10 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;

namespace Cosmos.Media.Play.IO
{
    /// <summary>
    /// Represents a writer that saves a play tree to a CPT file.
    /// </summary>
    public class CptWriter : IPlayTreeWriter, IDisposable
    {
        private const string _PlayTreeNodeElementName = "PlayTreeNode";
        private const string _PlayItemElementName = "PlayItem";
        private const string _NameAttributeName = "Name";
        private const string _DefaultNameAttributeValue = "NoName";
        private const string _PathAttributeName = "Path";
        private const string _TagElementName = "Tag";
        private const string _ValueAttributeName = "Value";
        private const string _AttributeAttributeName = "Attribute";
        private const string _InheritedAttributeName = "Inherited";
        private const string _MultipleAttributeName = "Multiple";

        private TextWriter _textWriter;
        private XmlWriter _xmlWriter;

        private string _defaultRootPath = null;

        public CptWriter(TextWriter textWriter)
            : this(textWriter, null)
        {

        }

        public CptWriter(TextWriter textWriter, string defaultRootPath)
        {
            _textWriter = textWriter;
            if (defaultRootPath == null || Path.IsPathRooted(defaultRootPath))
            {
                _defaultRootPath = defaultRootPath;
            }
            else
            {
                throw new ArgumentException("The path is not rooted path.", "defaultRootPath");
            }
        }

        public CptWriter(XmlWriter xmlWriter)
        {
            _xmlWriter = xmlWriter;
        }

        public void Close()
        {
            if (_textWriter != null)
            {
                _textWriter.Close();
            }

            if (_xmlWriter != null)
            {
                _xmlWriter.Close();
            }
        }

        public void Dispose()
        {
            if (_textWriter != null)
            {
                _textWriter.Dispose();
            }
        }

        public void Flush()
        {
            if (_textWriter != null)
            {
                _textWriter.Flush();
            }

            if (_xmlWriter != null)
            {
                _xmlWriter.Flush();
            }
        }

        public void Save(PlayTreeNode playTreeNode)
        {
            XDocument xDocument = new XDocument();
            xDocument.Add(SaveNodeToXml(playTreeNode));

            if (_textWriter != null)
            {
                xDocument.Save(_textWriter);
            }
            else if (_xmlWriter != null)
            {
                xDocument.Save(_xmlWriter);
            }
        }

        private XElement SaveNodeToXml(PlayTreeNode playTreeNode)
        {
            XElement nodeElement = new XElement(_PlayTreeNodeElementName);

            string nodeName = playTreeNode.Name;
            if (String.IsNullOrEmpty(nodeName))
                nodeName = _DefaultNameAttributeValue;
            nodeElement.Add(new XAttribute(_NameAttributeName, nodeName));

            // Writes all attributes.
            XElement attributeElement;
            XAttribute nameAttribute;
            XAttribute valueAttribute;
            XAttribute inheritedAttribute;
            XAttribute multipleAttribute;
            foreach (PlayAttribute anAttribute in playTreeNode.Attributes)
            {
                attributeElement = new XElement(_AttributeAttributeName);
                nameAttribute = new XAttribute(_NameAttributeName, anAttribute.Name);
                valueAttribute = new XAttribute(_ValueAttributeName, anAttribute.Value);
                inheritedAttribute = new XAttribute(_InheritedAttributeName, anAttribute.Inherited.ToString());
                multipleAttribute = new XAttribute(_MultipleAttributeName, anAttribute.AllowMultiple.ToString());

                attributeElement.Add(nameAttribute, valueAttribute, inheritedAttribute, multipleAttribute);
                nodeElement.Add(attributeElement);
            }
            multipleAttribute = null;
            inheritedAttribute = null;
            valueAttribute = null;
            nameAttribute = null;
            attributeElement = null;

            // Writes all sub-nodes.
            foreach (PlayTreeNode aNode in playTreeNode.Nodes)
            {
                nodeElement.Add(SaveNodeToXml(aNode));
            }

            // Writes all items.
            PlayList playList = playTreeNode.List;
            foreach (PlayListItem anItem in playList.Items)
            {
                nodeElement.Add(SaveItemToXml(anItem));
            }

            return nodeElement;
        }

        private XElement SaveItemToXml(PlayListItem playItem)
        {
            XElement itemElement = new XElement(_PlayItemElementName);

            XAttribute nameAttribute = new XAttribute(_NameAttributeName, playItem.Name);
            string itemPath = playItem.Path;
            if (_defaultRootPath != null && itemPath.Contains(_defaultRootPath))
            {
                itemPath = itemPath.Substring(_defaultRootPath.Length);
            }
            XAttribute pathAttribute = new XAttribute(_PathAttributeName, itemPath);
            itemElement.Add(nameAttribute, pathAttribute);

            // Writes all tags.
            XElement tagElement;
            XAttribute valueAttribute;
            foreach (string aTag in playItem.Tags)
            {
                tagElement = new XElement(_TagElementName);
                valueAttribute = new XAttribute(_ValueAttributeName, aTag);

                tagElement.Add(valueAttribute);
                itemElement.Add(tagElement);
            }
            valueAttribute = null;
            tagElement = null;

            // Writes all attributes.
            XElement attributeElement;
            XAttribute inheritedAttribute;
            XAttribute multipleAttribute;
            foreach (PlayAttribute anAttribute in playItem.Attributes)
            {
                attributeElement = new XElement(_AttributeAttributeName);
                nameAttribute = new XAttribute(_NameAttributeName, anAttribute.Name);
                valueAttribute = new XAttribute(_ValueAttributeName, anAttribute.Value);
                inheritedAttribute = new XAttribute(_InheritedAttributeName, anAttribute.Inherited.ToString());
                multipleAttribute = new XAttribute(_MultipleAttributeName, anAttribute.AllowMultiple.ToString());

                attributeElement.Add(nameAttribute, valueAttribute, inheritedAttribute, multipleAttribute);
                itemElement.Add(attributeElement);
            }
            multipleAttribute = null;
            inheritedAttribute = null;
            valueAttribute = null;
            nameAttribute = null;
            attributeElement = null;

            return itemElement;
        }
    }
}
